package ai.convolution;

import ai.MyDimension;
import ai.gui.LayoutHint;
import java.awt.Dimension;

public class LayerConfig {

    class NeuronConfig {

        int[] mod;
        int[] ptr;

        private NeuronConfig(int[] ptr1, int[] mods1) {
            mod = mods1;
            ptr = ptr1;
        }
    }
    NeuronConfig neurons[];
    boolean fix = false;
    MyDimension dKernel;
    MyDimension dUnitOut;
    boolean displayWeights = false;
    boolean displayOut = false;

    /**
     *
     * treat previous layer as 1 big block
     * create nUnit fully connected outputs
     *
     * @param prevLayer
     * @param nUnit
     */
    LayerConfig(LayerConfig prevLayer, int nNeuron) {

        dKernel = new MyDimension(nNeuron, prevLayer.dUnitOut.n);
        dUnitOut = new MyDimension(1, 1);
        //     this.nNeuron = nNeuron;

        //  MyDimension dUnitOut = new MyDimension(dSrc.width - dUnitIn.width + 1, dSrc.width - dUnitIn.width + 1);

        //    hiddenLayerSize = nUnit;

        neurons = new NeuronConfig[nNeuron];
        // mod = new int[nNeuron][];
        // ptr = new int[nNeuron][];

        // All units share same input pointersand modulations
        System.out.println(" Prev layer " + prevLayer.getSize());
        int[] ptr1 = new int[prevLayer.getSize()];
        int[] mods1 = new int[1];


        for (int k = 0; k < ptr1.length; k++) {
            ptr1[k] = k;
        }


        mods1[0] = 0;

        for (int i = 0; i < nNeuron; i++) {
            neurons[i] = new NeuronConfig(ptr1, mods1);
        }
        displayOut = false;
        displayWeights = false;

    }

    /**
     * create layer parameters for units of same dimension as the source image.#
     * No convolution.c
     * 
     * @param dSrc
     * @param nUnit
     */
    LayerConfig(MyDimension dSrc, int nNeuron) {
        super();

        dKernel = dSrc;
        dUnitOut = new MyDimension(1, 1);
        //     this.nNeuron = nNeuron;
        //  MyDimension dUnitOut = new MyDimension(dSrc.width - dUnitIn.width + 1, dSrc.width - dUnitIn.width + 1);

        //    hiddenLayerSize = nUnit;

        neurons = new NeuronConfig[nNeuron];

        // All units share same input pointersand modulations
        int[] ptr1 = new int[dSrc.n];
        int[] mods1 = new int[1];


        for (int k = 0; k < dSrc.n; k++) {
            ptr1[k] = k;
        }


        mods1[0] = 0;

        for (int i = 0; i < nNeuron; i++) {
            neurons[i] = new NeuronConfig(ptr1, mods1);
        }
    }

    int getSize() {
        return neurons.length * dUnitOut.n;
    }

    /**
     * 
     * 
     * @param dSrc
     * @param dKernel
     * @param nUnit
     */
    LayerConfig(MyDimension dSrc, MyDimension dKernel, int nNeuron) {
        super();
        this.dKernel = dKernel;
//        this.nNeuron = nNeuron;
        dUnitOut = new MyDimension(dSrc.width - dKernel.width + 1, dSrc.height - dKernel.height + 1);

        //      hiddenLayerSize = nUnit * dUnitOut.n;
        neurons = new NeuronConfig[nNeuron];

        // All units share same input pointersand modulations
        int[] ptr1 = new int[dKernel.n];
        int[] mods1 = new int[dUnitOut.n];


        int k = 0;
        for (int j = 0; j < dKernel.height; j++) {
            for (int i = 0; i < dKernel.width; i++, k++) {
                ptr1[k] = dSrc.index(i, j);
            }
        }

        k = 0;
        for (int j = 0; j < dUnitOut.height; j++) {
            for (int i = 0; i < dUnitOut.width; i++, k++) {
                mods1[k] = dSrc.index(i, j);

            }
        }
        for (int i = 0; i < nNeuron; i++) {
            neurons[i] = new NeuronConfig(ptr1, mods1);
        }

    }

    static public LayeredBrain createConvolutionBrain1(Dimension dIn, Dimension dOut) {

        LayerConfig config[] = new LayerConfig[1];
        config[0] = new LayerConfig(new MyDimension(dIn), 10);
        config[0].displayWeights = true;
        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);

        return brain;
    }

//    static public LayeredBrain createConvolutionBrain2(Dimension dIn, Dimension dOut) {
//
//        LayerConfig config[] = new LayerConfig[2];
//
//        config[0] = new LayerConfig(new MyDimension(dIn), 10);
//        config[0].displayWeights = true;
//
//        config[1] = new LayerConfig(new MyDimension(1, config[0].getSize()), 10);
//
//        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);
//
//        return brain;
//    }

    static public LayeredBrain createConvolutionBrain3(Dimension dIn, Dimension dOut, int nHidden) {

        LayerConfig config[] = new LayerConfig[2];

        config[0] = new LayerConfig(new MyDimension(dIn), nHidden);
        config[0].displayWeights = true;

        config[1] = new LayerConfig(new MyDimension(1, nHidden), dOut.width * dOut.height);

        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);

        return brain;
    }

    static public LayeredBrain createConvolutionBrain4(Dimension dIn, Dimension dOut, int nType) {

     //   nType = 1;
        LayerConfig config[] = new LayerConfig[2];

        MyDimension dKernel = new MyDimension(1, 1);

        config[0] = new LayerConfig(new MyDimension(dIn), dKernel, nType);
//        config[0].dOut=new MyDimension(dIn);
        //     config[0].fix=true;
        config[0].displayWeights = true;
        config[0].displayOut = true;

        config[1] = new LayerConfig(new MyDimension(dIn),
                dOut.width * dOut.height);
        config[1].dKernel = config[0].dUnitOut;
        config[1].displayWeights = true;
        //     config[0].displayOut=true;

        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);

        return brain;
    }

    static public LayeredBrain createConvolutionBrain5(Dimension dIn, Dimension dOut,int nNeuron,int nK) {

      //  int nNeuron = 4;
        LayerConfig config[] = new LayerConfig[2];

        MyDimension dKernel = new MyDimension(nK, nK);

        config[0] = new LayerConfig(new MyDimension(dIn), dKernel,  nNeuron);
        config[0].displayWeights = true;
        config[0].displayOut = true;


        config[1] = new LayerConfig(config[0], dOut.height * dOut.width);

        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);
        brain.hint=new LayoutHint(10);
        return brain;
    }

    static public LayeredBrain createConvolutionBrain6(Dimension dIn, Dimension dOut,
            int nNeuron,int nK,int nHidden) {

        LayerConfig config[] = new LayerConfig[3];

        MyDimension dKernel = new MyDimension(nK, nK);

        config[0] = new LayerConfig(new MyDimension(dIn), dKernel,  nNeuron);
        config[0].displayWeights = true;
        config[0].displayOut = true;


        config[1] = new LayerConfig(config[0], nHidden);

        config[2] = new LayerConfig(config[1], dOut.height * dOut.width);

        LayeredBrain brain = new LayeredBrain(dIn, dOut, config);
        brain.hint=new LayoutHint(10);
        return brain;
    }

}
